feat(extensions): let extensions contribute always-on instructions - #4259
feat(extensions): let extensions contribute always-on instructions#4259TheovanKraay wants to merge 4 commits into
Conversation
…ithub#4200) Adds a provides.instructions capability so an extension can ship a compact always-on rule block that reaches the agent without any command/hook invocation. Ownership per maintainer decision: core validates the metadata only; the opt-in agent-context extension composes and owns the agent-file writes (namespaced <!-- SPECKIT EXT:<id> START/END --> blocks, per-agent routing, enable/disable/remove lifecycle). No agent-file writes when agent-context is not installed. core: accept+validate provides.instructions (path-safe, instructions-only extension allowed), expose .instructions. agent-context: compose enabled extensions' instruction blocks into the routed context file; bash/ps1 twins delegate to the python twin's --emit-extension-blocks for byte-identical output. Tests: tests/extensions/test_extension_instructions.py (13). Evidence: extensions/agent-context/INSTRUCTIONS-POC-EVIDENCE.md.
There was a problem hiding this comment.
Pull request overview
Adds opt-in, always-on extension instructions composed through agent-context.
Changes:
- Validates
provides.instructionsmanifests. - Composes enabled extensions’ instruction blocks across script variants.
- Adds validation/composition tests and supporting evidence.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/extensions/__init__.py |
Adds manifest validation and accessor. |
extensions/agent-context/scripts/python/update_agent_context.py |
Collects and renders instruction blocks. |
extensions/agent-context/scripts/bash/update-agent-context.sh |
Delegates block rendering to Python. |
extensions/agent-context/scripts/powershell/update-agent-context.ps1 |
Delegates block rendering to Python. |
tests/extensions/test_extension_instructions.py |
Tests validation and composition. |
extensions/agent-context/INSTRUCTIONS-POC-EVIDENCE.md |
Documents the prototype and evidence. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…on payloads; ps1 PyYAML probe; docs + evidence Copilot PR review (github#4259) fixes: - update_agent_context.py: reject instruction payloads that embed a managed-section marker (outer markers or per-extension SPECKIT EXT markers) so _upsert_section cannot strand content on disable/remove; catch UnicodeDecodeError (not just OSError) so a non-UTF-8 file is skipped instead of crashing the refresh. Markers threaded through the collector/render helpers. - update-agent-context.ps1: the emit-blocks interpreter probe now requires 'import yaml' (mirrors the config-parse probe) so a python3 without PyYAML is not selected. - EXTENSION-API-REFERENCE.md + EXTENSION-DEVELOPMENT-GUIDE.md: document provides.instructions (schema, path rules, opt-in agent-context behavior + lifecycle). - INSTRUCTIONS-POC-EVIDENCE.md: use the verified +0.123 (22/0/2, n=24) install-path figure and mark the earlier +0.142 as a distinct pilot; refresh suite counts; clarify the trigger/lifecycle model. - tests: add marker-collision-skip and non-UTF-8-skip cases (15 passing).
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
Suppressed comments (1)
extensions/agent-context/scripts/python/update_agent_context.py:493
- This composition only runs when the update script is invoked. The extension add/remove/enable/disable paths only refresh native events, and
agent-contextregisters onlyafter_specify/after_planhooks, so adding an instructions extension leaves the context file unchanged until a user or agent invokes a command/hook; disable/remove likewise leaves stale rules until then. That contradicts the PR's “without any command or hook being invoked” guarantee and #4200's install/lifecycle acceptance criteria. Add an agent-context-owned extension-lifecycle refresh and cover add, enable, disable, remove, and update end to end.
extension_blocks = _render_extension_block_lines(project_root, marker_start, marker_end)
section = _build_section(marker_start, marker_end, plan_path, extension_blocks)
…t parity test for composed instructions - __init__.py: reject a present non-string provides.instructions[].description, matching the docs and the command/template/script validators. - test_update_agent_context_python_parity.py: add an installed-instructions fixture and compare Python/Bash/PowerShell resulting context bytes incl. a non-ASCII payload (bash gated to POSIX CI; PowerShell parity verified locally). - test_extension_instructions.py: add non-string-description validation test.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
extensions/agent-context/INSTRUCTIONS-POC-EVIDENCE.md:58
- This count is stale: the file contains 14 test functions, and the three-case parametrization produces 16 collected test cases.
`tests/extensions/test_extension_instructions.py` (13 tests, all passing):
…PowerShell has no Python for composition - emitter (--emit-extension-blocks) now accepts --marker-start/--marker-end; bash and ps1 twins forward their configured markers so collision-rejection uses the SAME markers the upsert uses (fixes custom-marker payload collisions, not just default SPECKIT markers). - ps1: when no Python 3 + PyYAML is on PATH but other extensions are installed, warn that provides.instructions blocks were not composed instead of silently writing only the base section (bash already requires Python for its upsert, so it cannot silently omit). - tests: custom-marker forwarding + collision-rejection unit tests; custom-marker byte-parity tests for bash (POSIX CI) and PowerShell (passes locally).
Description
Part of #4200.
Adds a
provides.instructionscapability so a Spec Kit extension can ship a compact,always-on rule block that reaches the agent without any command or hook being invoked —
the reachability gap discussed in #4200. Ownership follows what we agreed on in the thread:
agent-contextextension composes enabled extensions' blocks into the routedagent file (
.github/copilot-instructions.md,CLAUDE.md, …) as namespaced<!-- SPECKIT EXT:<id> START/END -->blocks, and owns routing, refresh, update, and removal.agent-contextisn't installed, nothing touches any agent file. The key is additive anda no-op on cores without this change.
Why it's needed: today nothing delivers an extension's guidance automatically on install in a way
that survives a hands-off agent run. This adds that always-on channel, scoped to an opt-in extension.
Efficacy (same rule block + conformance metric throughout):
0.843, B always-on0.986,C rules in an invoked command
0.989, D same command never invoked0.831.C − B = +0.003,payload present for B/C and absent for D — so the effect is reachability (present vs absent), not
obedience.
22 wins / 0 ties / 2 losses. The block that lands in
copilot-instructions.mdon a real installis byte-identical to the one measured.
One test not completed (for transparency): a behavioral A/B on an internal at-scale agent-execution
harness is currently inconclusive due to an agent-runtime regression unrelated to this change — the
agent crashed on startup on every attempt (both arms, incl. bare), confirmed by an untouched baseline
image failing identically. In-container delivery of the block was verified separately. That datapoint
is pending a healthy agent build and is not reported as a result.
Testing
uv run specify --helpuv sync && uv run pytestNew tests
tests/extensions/test_extension_instructions.py: 13 passed (validation accept/reject,composition, disable-cleanup, multi-extension ordering, path-unsafe skip, no-op without
agent-context,emit mode). Full suite on this branch, rebased on current
main: 6916 passed, 415 skipped, 0 failed.bash/powershell/pythonemit paths verified byte-identical. End-to-end verified in a sampleproject: after
specify extension add <ext> --dev+specify extension add /agent-context --dev, thenamespaced block appears in
.github/copilot-instructions.md, and enable/disable/remove clean up correctly.AI Disclosure
Implemented with GitHub Copilot (agentic) — the core validation, the
agent-contextcompose logic andits bash/powershell/python twins, and the test suite were written with AI assistance and reviewed by me.
The empirical evaluation (the pre-check and the +0.123 conformance measurement) was also run and analyzed
with AI assistance.